package util

import (
	"fmt"
	"gitee.com/manoshi/go-util/exception"
	"math"
	"time"
)

const formatSimple0 = "2006-01-02 15:04:05.000"
const formatSimple1 = "2006-01-02 15:04:05"
const formatSimple2 = "2006-01-02"
const formatSimple3 = "20060102"
const formatSimple4 = "2006-01"
const DayStart = "00:00:00"
const DayEnd = "23:59:59"

func FormatMonth(dateTime time.Time) string {
	return dateTime.Format(formatSimple4)
}
func FormatDate(dateTime time.Time) string {
	return dateTime.Format(formatSimple2)
}
func FormatDates(dateTime time.Time) string {
	return dateTime.Format(formatSimple3)
}

//FormatDateTime 格式 yyyy-MM-dd HH:mm:ss
func FormatDateTime(dateTime time.Time) string {
	return dateTime.Format(formatSimple1)
}

func FormatDateMillTime(dateTime time.Time) string {
	return dateTime.Format(formatSimple0)
}
func GetMonthStart(dateTime time.Time) time.Time {
	return time.Date(dateTime.Year(), dateTime.Month(), 1, dateTime.Hour(), dateTime.Minute(), dateTime.Second(), dateTime.Nanosecond(), time.UTC)
}
func GetMonthEnd(dateTime time.Time) time.Time {
	return time.Date(dateTime.Year(), dateTime.Month()+1, 1, dateTime.Hour(), dateTime.Minute(), dateTime.Second(), dateTime.Nanosecond(), time.UTC).AddDate(0, 0, -1)
}

func ParseDateStart(date string) time.Time {
	d := ParseDate(date)
	return Start(d)
}

func ParseDateEnd(date string) time.Time {
	d := ParseDate(date)
	return End(d)
}

func ParseMonth(date string) time.Time {
	stamp, err := time.ParseInLocation(formatSimple4, date, time.Local)
	exception.AssertThrowable(err != nil, "SYSTEM_ERR.TIME_INVALID", fmt.Sprintf("[%s]日期格式错误,正确格式为：年-月", date))
	return stamp
}

func ParseDate(date string) time.Time {
	stamp, err := time.ParseInLocation(formatSimple2, date, time.Local)
	exception.AssertThrowable(err != nil, "SYSTEM_ERR.TIME_INVALID", fmt.Sprintf("[%s]日期格式错误,正确格式为：年-月-日", date))
	return stamp
}

func ParseDateTime(dateTime string) time.Time {
	stamp, err := time.ParseInLocation(formatSimple1, dateTime, time.Local)
	exception.AssertThrowable(err != nil, "SYSTEM_ERR.TIME_INVALID", fmt.Sprintf("[%s]时间格式错误,正确格式为：年-月-日 时(24小时制):分:秒", dateTime))
	return stamp
}

func ParseDateTimeE(dateTime string, errMsg string) time.Time {
	stamp, err := time.ParseInLocation(formatSimple1, dateTime, time.Local)
	exception.AssertThrowable(err != nil, "SYSTEM_ERR.TIME_INVALID", errMsg)
	return stamp
}

func AddYear(date time.Time, d int) time.Time {
	return date.AddDate(d, 0, 0)
}

func AddMonth(date time.Time, d int) time.Time {
	return date.AddDate(0, d, 0)
}

func AddDate(date time.Time, d int) time.Time {
	return date.AddDate(0, 0, d)
}

func Add(date time.Time, d int64) time.Time {
	t := date.Unix()
	t += d //增加秒
	return time.Unix(t, int64(date.Nanosecond()))
}
func StartHour(date time.Time) time.Time {
	return time.Date(date.Year(), date.Month(), date.Day(), date.Hour(), 0, 0, 0, date.Location())
}

func EndHour(date time.Time) time.Time {
	return time.Date(date.Year(), date.Month(), date.Day(), date.Hour(), 59, 59, 0, date.Location()).Add(time.Second - time.Millisecond)
}
func Start(date time.Time) time.Time {
	return time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, date.Location())
}

func End(date time.Time) time.Time {
	return time.Date(date.Year(), date.Month(), date.Day(), 23, 59, 59, 0, date.Location()).Add(time.Second - time.Millisecond)
}

/*
SpanMonths
计算两时间跨度多少个月（例如：2000-01-01到2000-06-01跨度6个月）
*/
func SpanMonths(startDateTime, endDateTime *time.Time) (month int) {
	y1 := startDateTime.Year()
	y2 := endDateTime.Year()
	m1 := int(startDateTime.Month())
	m2 := int(endDateTime.Month())
	subMonth := math.Abs(float64(y2*12 + m2 - y1*12 - m1))
	return int(subMonth) + 1
}

/*
SpanDays
计算两时间跨度多少天
*/
func SpanDays(startDateTime, endDateTime *time.Time) int {
	if startDateTime.Location().String() != endDateTime.Location().String() {
		return -1
	}
	hours := math.Abs(endDateTime.Sub(*startDateTime).Hours())
	return int(hours/24) + 1
}

/*
SpanMinute
计算两时间跨度多少分钟
*/
func SpanMinute(startDateTime, endDateTime *time.Time) int {
	if startDateTime.Location().String() != endDateTime.Location().String() {
		return -1
	}
	minutes := math.Abs(endDateTime.Sub(*startDateTime).Minutes())
	return int(minutes) + 1
}

//TimeSubMinute 计算两时间相差分钟数(向上取整)
func TimeSubMinute(endDateTime, startDateTime *time.Time) int {
	if startDateTime.Location().String() != endDateTime.Location().String() {
		return -1
	}
	seconds := endDateTime.Sub(*startDateTime).Seconds()
	return int(math.Ceil(seconds / 60)) //向上取整
}

//TimeSubMinuteFloor 计算两时间相差分钟数(向下取整)
func TimeSubMinuteFloor(endDateTime, startDateTime *time.Time) int {
	if startDateTime.Location().String() != endDateTime.Location().String() {
		return -1
	}
	seconds := endDateTime.Sub(*startDateTime).Seconds()
	return int(math.Floor(seconds / 60)) //向下取整
}

//获取13位毫秒的时间戳
func MilSecond(time time.Time) int64 {
	return time.UnixMilli()
}

//获取10位秒的时间戳
func Second(time time.Time) int64 {
	return time.Unix()
}

// GetYearMonthToDay 查询指定年份指定月份有多少天
// @params year int 指定年份
// @params month int 指定月份
func GetYearMonthToDay(year int, month int) int {
	// 有31天的月份
	day31 := map[int]struct{}{
		1:  {},
		3:  {},
		5:  {},
		7:  {},
		8:  {},
		10: {},
		12: {},
	}
	if _, ok := day31[month]; ok {
		return 31
	}
	// 有30天的月份
	day30 := map[int]struct{}{
		4:  {},
		6:  {},
		9:  {},
		11: {},
	}
	if _, ok := day30[month]; ok {
		return 30
	}
	// 计算是平年还是闰年
	if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
		// 得出2月的天数
		return 29
	}
	// 得出2月的天数
	return 28
}

func WeekFirstDayTime(date time.Time) time.Time {
	weekday := date.Weekday()
	return AddDate(date, int(weekday)*-1+1)
}

func WeekEndDayTime(date time.Time) time.Time {
	weekday := date.Weekday()
	return AddDate(date, 7-int(weekday))
}

func MonthFirstDayTime(date time.Time) time.Time {
	month := date.Day()
	return AddDate(date, int(month)*-1+1)
}

func MonthEndDayTime(date time.Time) time.Time {
	month := date.Day()
	return AddDate(date, GetYearMonthToDay(date.Year(), int(date.Month()))-int(month))
}

func YearFirstDayTime(date time.Time) time.Time {
	return time.Date(date.Year(), time.January, 1, date.Hour(), date.Minute(), date.Second(), date.Nanosecond(), date.Location())
}

func YearEndDayTime(date time.Time) time.Time {
	return time.Date(date.Year(), time.December, 31, date.Hour(), date.Minute(), date.Second(), date.Nanosecond(), date.Location())
}
